import tileShader from './Shader/tile.wgsl?raw'
// import colorVert from '../Shader/'
import extentShader from './Shader/extent.wgsl?raw';
import { mat4, vec3 } from 'gl-matrix';
import Camera from '../Scene/Camera';
import Tile from '../Scene/Tile';
import Scene from '../Scene/Scene';
import { Cartesian3, BoundingSphere, Ellipsoid, Cartesian2, Cartographic, Math as CesiumMath, Rectangle } from 'cesium';
import Object3D from '@/Scene/Object3D';
// 创建一个初始矩阵（通常是单位矩阵）
export default class Renderer {
    private canvas: HTMLCanvasElement;
    private adapter: GPUAdapter;
    device: GPUDevice;
    private context: GPUCanvasContext;
    private pipeline: GPURenderPipeline;
    vertexBuffer1: GPUBuffer;
    indexBuffer: GPUBuffer;
    texture1: GPUTexture;
    sampler: GPUSampler;
    perspectiveMatrix: mat4;
    modelMatrix: mat4;
    viewMatrix: mat4;
    texTurebindGroup1: GPUBindGroup;
    MatrixBindgroup: GPUBindGroup;
    modelMatrixBuffer: GPUBuffer;
    viewMatrixBuffer: GPUBuffer;
    perspectiveMatrixBuffer: GPUBuffer;
    texbindGroupLayout: GPUBindGroupLayout;
    uint16indices: Uint16Array;
    isMouseDown: boolean;
    lastMouseX: number;
    lastMouseY: number;
    lastTime: number;
    Xangle: number;
    Zangle: number;
    distance: number;
    uRoateMatrix: mat4;
    uTranslateMatrix: mat4;
    vertexBuffer2: GPUBuffer;
    texTurebindGroup2: GPUBindGroup;
    texture2: GPUTexture;
    uvBuffer: GPUBuffer;
    _toDrawTiles: Tile[] = [];
    vertexBuffers: GPUBuffer[] = [];
    textures: GPUTexture;
    buffer3: GPUBuffer;
    indexBindGroup: GPUBindGroup;
    camera: Camera;
    scene: Scene;
    extentVertex: GPUBuffer;
    extentPipeline: GPURenderPipeline;
    toDrawObject3Ds: Object3D[] = [];
    constructor(canvas: HTMLCanvasElement, toDrawTiles: Tile[], scene: Scene) {
        this.scene = scene;
        this.canvas = canvas;
        this.uRoateMatrix = mat4.create();
        this.uTranslateMatrix = mat4.create();
        this.distance = 0;
        this.lastMouseX = 0;
        this.lastMouseY = 0;
        this.Xangle = -Math.PI / 2;
        this.Zangle = 0;
        this.lastTime = Date.now();
        this.camera = this.scene.camera;
        this._toDrawTiles = toDrawTiles;
    }


    public set toDrawTiles(tiles: Tile[]) {
        this._toDrawTiles = tiles;
    }


    async init() {
        // 获取适配器和设备
        this.adapter = await navigator.gpu.requestAdapter();
        this.device = await this.adapter.requestDevice();
        this.canvas.width = this.canvas.clientWidth * devicePixelRatio
        this.canvas.height = this.canvas.clientHeight * devicePixelRatio
        // 获取 canvas 上下文
        this.context = this.canvas.getContext('webgpu') as GPUCanvasContext;
        // 配置 canvas 的大小和格式
        const format = 'bgra8unorm';
        this.context.configure({
            device: this.device,
            format: format
        });
        const bindGroupLayout1 = this.device.createBindGroupLayout({
            entries: [
                {
                    binding: 0,
                    visibility: GPUShaderStage.VERTEX, // 这些 uniform 变量在顶点着色器中使用
                    buffer: {
                        type: 'uniform',
                        hasDynamicOffset: false, // 假设这里不使用动态偏移量
                    },
                },
                {
                    binding: 1,
                    visibility: GPUShaderStage.VERTEX,
                    buffer: {
                        type: 'uniform',
                        hasDynamicOffset: false,
                    },
                },
                {
                    binding: 2,
                    visibility: GPUShaderStage.VERTEX,
                    buffer: {
                        type: 'uniform',
                        hasDynamicOffset: false,
                    },
                },
                // 其他绑定项...
            ],
        });
        // 绑定组布局 0
        const bindGroupLayout0 = this.device.createBindGroupLayout({
            entries: [
                {
                    binding: 0,
                    visibility: GPUShaderStage.FRAGMENT, // 采样器在片段着色器中使用
                    sampler: {
                        type: 'filtering',
                    },
                },
                {
                    binding: 1,
                    visibility: GPUShaderStage.FRAGMENT, // 纹理数组在片段着色器中使用
                    texture: {
                        sampleType: 'float',
                        viewDimension: '2d-array',
                    },
                },
            ],
        });

        // 绑定组布局 2 
        const bindGroupLayout2 = this.device.createBindGroupLayout({
            entries: [
                {
                    binding: 0,
                    visibility: GPUShaderStage.FRAGMENT, // 整数统一变量在片段着色器中使用
                    buffer: {
                        type: 'uniform',
                        hasDynamicOffset: true, // 假设这里不使用动态偏移量
                        // minBindingSize: 0, // 指定绑定大小为 4 字节
                    },
                },
            ],
        });
        const pipelineLayout = this.device.createPipelineLayout({
            bindGroupLayouts: [bindGroupLayout0, bindGroupLayout1, bindGroupLayout2],
        });
        //初始化渲染管线
        this.pipeline = this.device.createRenderPipeline({
            layout: pipelineLayout,
            vertex: {
                module: this.device.createShaderModule({
                    code: tileShader
                }),
                buffers: [{
                    arrayStride: 3 * 4,
                    attributes: [{
                        format: 'float32x3',
                        offset: 0,
                        shaderLocation: 0
                    }]
                }, {
                    arrayStride: 2 * 4,
                    attributes: [{
                        format: 'float32x2',
                        offset: 0,
                        shaderLocation: 1
                    }]
                }],
                entryPoint: 'vs_main'
            },
            primitive: {
                topology: 'triangle-list', // try point-list, line-list, line-strip, triangle-strip?
                // 开启背面剔除
                cullMode: 'back',
            },
            fragment: {
                module: this.device.createShaderModule({
                    code: tileShader
                }),
                entryPoint: 'fs_main',
                targets: [
                    {
                        format: format
                    }
                ]
            }
        });
        this.initIndexbuffer();
        this.initUvBuffer();
        this.setTilePositionBuffer();
        this.initTexture();
        this.setMvpMatrix();
        this.bindEvents();

    }
    setTilePositionBuffer() {
        this._toDrawTiles.forEach((tile) => {
            let floatvertices = new Float32Array(tile.positions);
            // 创建顶点缓冲区和索引缓冲区
            let vertexBuffer = this.device.createBuffer({
                size: floatvertices.byteLength,
                usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
            });
            this.device.queue.writeBuffer(vertexBuffer, 0, floatvertices);//写入数据
            this.vertexBuffers.push(vertexBuffer);
        })
        let size = new Float32Array(this._toDrawTiles[0].positions).byteLength
        for (let index = 0; index < 100; index++) {
            let vertexBuffer = this.device.createBuffer({
                size: size,
                usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
            });
            this.vertexBuffers.push(vertexBuffer);
        }
    }
    initIndexbuffer() {
        const indices = [];
        //间隔顶点理论，这个得注意一下
        for (let lat = 0; lat < 99; lat++) {
            for (let lng = 0; lng < 199; lng++) {
                const first = (lat * 200) + lng;
                const second = first + 200;
                indices.push(first, second, first + 1);
                indices.push(second, second + 1, first + 1);
            }
        }
        // console.log(indices.length);
        this.uint16indices = new Uint16Array(indices);
        this.indexBuffer = this.device.createBuffer({
            size: this.uint16indices.byteLength,
            usage: GPUBufferUsage.INDEX,
            mappedAtCreation: true
        });
        new Uint16Array(this.indexBuffer.getMappedRange()).set(this.uint16indices);
        this.indexBuffer.unmap();
        // 每个元素需要的总字节数（包括填充）

        let offset = this._toDrawTiles.map((tile, index) => {
            return index
        })
        for (let index = 16; index < 116; index++) {
            const element = offset.push(index);
        }
        //设置偏移
        const data = new Int32Array(offset);
        const bytesPerElement = 256;

        // 创建一个足够大的 ArrayBuffer 来存储数据和填充
        const buffer = new ArrayBuffer(data.length * bytesPerElement);

        // 使用 DataView 来操作 ArrayBuffer
        const view = new DataView(buffer);

        // 将数据写入 DataView，每个元素后都添加填充
        for (let i = 0; i < data.length; i++) {
            view.setInt32(i * bytesPerElement, data[i], true); // 假设使用小端字节序
        }

        this.buffer3 = this.device.createBuffer({
            size: buffer.byteLength,
            usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
        });
        this.device.queue.writeBuffer(this.buffer3, 0, new Uint8Array(buffer));

        // 创建绑定组，将缓冲区绑定到绑定点 0
        this.indexBindGroup = this.device.createBindGroup({
            layout: this.pipeline.getBindGroupLayout(2),
            entries: [{
                binding: 0,
                resource: {
                    buffer: this.buffer3,
                    size: 4 * 4
                },
            }],
        });
    }
    initUvBuffer() {
        const uv = [];
        for (let lat = 0; lat < 100; lat++) {
            for (let lng = 0; lng < 200; lng = lng + 1) {
                const u = lng / 199;
                const v = lat / 99;
                uv.push(u, v);
            }
        }
        // console.log(uv.length / 2);
        this.uvBuffer = this.device.createBuffer({
            size: new Float32Array(uv).byteLength,
            usage: GPUBufferUsage.VERTEX,
            mappedAtCreation: true
        })
        new Float32Array(this.uvBuffer.getMappedRange()).set(new Float32Array(uv));
        this.uvBuffer.unmap();
    }

    initTexture() {
        this.sampler = this.device.createSampler({
            magFilter: 'linear',
            minFilter: 'linear',
        });
        const textureSize = { width: 256, height: 256, depthOrArrayLayers: 116 };
        this.textures = this.device.createTexture({
            size: textureSize,
            format: 'rgba8unorm',
            usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_DST,
            dimension: '2d',
        });
        this.texTurebindGroup1 = this.device.createBindGroup({
            layout: this.pipeline.getBindGroupLayout(0),
            entries: [
                {
                    binding: 0,
                    resource: this.sampler,
                },
                {
                    binding: 1,
                    resource: this.textures.createView(),
                },
            ],
        });

    }
    /**
     * @description: 更新顶点和纹理
     */

    UpdateData() {
        let bitmaps = this._toDrawTiles.map((tile) => {
            return tile.texture;
        });
        // console.log(this._toDrawTiles[0].positions.length);
        const containsUndefined = bitmaps.includes(undefined);
        if (!containsUndefined) {
            for (let i = 0; i < this._toDrawTiles.length; i++) {
                let floatvertices = new Float32Array(this._toDrawTiles[i].positions);
                this.device.queue.writeBuffer(this.vertexBuffers[i], 0, floatvertices);
                this.device.queue.copyExternalImageToTexture(
                    { source: bitmaps[i] },
                    { texture: this.textures, origin: { x: 0, y: 0, z: i } },
                    [256, 256, 1]
                )
            }
        }

    }
    UpdateTileVertex() {
        if (this._toDrawTiles.length !== 16) {
            // debugger
        }
        this._toDrawTiles.forEach((tile, index) => {
            let floatvertices = new Float32Array(tile.positions);
            this.device.queue.writeBuffer(this.vertexBuffers[index], 0, floatvertices);
        })
    }
    setMvpMatrix() {
        //模型矩阵
        this.modelMatrix = mat4.create();
        this.modelMatrixBuffer = this.device.createBuffer({
            size: 64, // 4x4 矩阵，每个元素为float32
            usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
        });
        GPUBufferUsage.VERTEX
        // 更新缓冲区数据
        this.device.queue.writeBuffer(this.modelMatrixBuffer, 0, this.modelMatrix as Float32Array);
        //视图矩阵
        let viewMatrix = new Float32Array(this.camera.ViewMatrix);
        this.viewMatrixBuffer = this.device.createBuffer({
            size: 64, // 4x4 矩阵，每个元素为float32
            usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
        });
        this.device.queue.writeBuffer(this.viewMatrixBuffer, 0, viewMatrix);
        //投影矩阵
        this.perspectiveMatrix = mat4.create();
        this.perspectiveMatrixBuffer = this.device.createBuffer({
            size: 64, // 4x4 矩阵，每个元素为float32
            usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
        });
        let projectmatrix = new Float32Array(this.camera.frustum.ProjectionMatrix);
        this.device.queue.writeBuffer(this.perspectiveMatrixBuffer, 0, projectmatrix);
        this.MatrixBindgroup = this.device.createBindGroup({
            layout: this.pipeline.getBindGroupLayout(1),
            entries: [
                {
                    binding: 0,
                    resource: {
                        buffer: this.modelMatrixBuffer,
                    },
                },
                {
                    binding: 1,
                    resource: {
                        buffer: this.viewMatrixBuffer,
                    },
                },
                {
                    binding: 2,
                    resource: {
                        buffer: this.perspectiveMatrixBuffer,
                    },
                },
            ],
        })
    }

    bindEvents() {
        this.canvas.addEventListener('mousedown', (event) => {
            this.isMouseDown = true;
            this.lastMouseX = event.clientX;
            this.lastMouseY = event.clientY;
        });

        this.canvas.addEventListener('mousemove', (event) => {
            if (this.isMouseDown) {
                let currentTime = Date.now();
                //节流
                if (currentTime - this.lastTime > 80) {
                    let deltaX = event.clientX - this.lastMouseX;
                    let deltaY = event.clientY - this.lastMouseY;
                    let Xangle = 0;
                    let Zangle = 0;
                    let sphere = new BoundingSphere(Cartesian3.ZERO, 6378137)
                    let distance = this.camera.distanceToBoundingSphere(sphere);
                    let ratio = distance / this.camera.initDistance;
                    if (Math.abs(deltaY) > 10) {
                        Xangle = -deltaY * Math.PI / 320 * ratio;
                    }
                    if (Math.abs(deltaX) > 10) {
                        Zangle = -deltaX * Math.PI / 320 * ratio;
                    }
                    this.roate(Xangle, 0, Zangle);
                    this.lastMouseX = event.clientX;
                    this.lastMouseY = event.clientY;
                    this.lastTime = currentTime;
                }// 50毫秒的节流间隔}
            }
        });

        this.canvas.addEventListener('mouseup', (event) => {
            this.isMouseDown = false;
        });
        this.canvas.addEventListener("wheel", (event) => {
            let sphere = new BoundingSphere(Cartesian3.ZERO, 6378137)
            this.distance = this.camera.distanceToBoundingSphere(sphere);
            var delta = Math.sign(event.deltaY);
            Math.exp(delta * 0.1);
            // 根据滚轮的方向调整缩放比例
            if (delta < 0) {
                // 向下滚动，相机靠近地球
                if (this.distance > 500) {
                    let newdistance = this.distance * 0.05;
                    this.translate(0, 0, newdistance);
                }
            } else {
                let newdistance = this.distance * 0.05;
                this.translate(0, 0, -newdistance);
            }
            // this.camera.computeViewRectangle();
            // 阻止默认的滚动行为
            event.preventDefault();
            // 获取鼠标滚轮的滚动方向和距离

        });
        this.canvas.addEventListener('click', (event) => {
            let extent = this.camera.computeViewRectangle();
            // console.log(extent.south * 180 / Math.PI, extent.north * 180 / Math.PI);
            let windowPosition = new Cartesian2(event.clientX, event.clientY);
            let cartesian3 = this.camera.pickEllipsoid(windowPosition, Ellipsoid.WGS84);
            if (cartesian3) {
                let cartographic = Cartographic.fromCartesian(cartesian3);
                let longitude = CesiumMath.toDegrees(cartographic.longitude);
                let latitude = CesiumMath.toDegrees(cartographic.latitude);
                // console.log(latitude);
                // if (latitude <= extent.north * 180 / Math.PI && latitude >= extent.south * 180 / Math.PI) {
                //     console.log('在范围内');
                // } else {
                //     console.log('不在范围内');
                // }
            }
        })

    }
    translate(x: number, y: number, z: number) {
        this.camera.moveForward(z);
        let viewMatrix = this.camera.ViewMatrix;
        this.toDrawObject3Ds[0].setViewMatrix(viewMatrix);
        this.device.queue.writeBuffer(this.viewMatrixBuffer, 0, new Float32Array(viewMatrix));
        let extent = this.camera.computeViewRectangle();
        this.scene._quadtreePrimitive.selectTilesToRender(extent);

        // if (extent) {
        //     // let points = this.createPointsForExtent(extent);
        //     // console.log(points.length / 3);
        //     // this.extentVertex = this.device.createBuffer({
        //     //     size: new Float32Array(points).byteLength,
        //     //     usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
        //     // });
        //     // this.device.queue.writeBuffer(this.extentVertex, 0, new Float32Array(points));
        // }
    }
    roate(Xangle: number, Yangle: number, Zangle: number) {
        this.camera.rotate(Xangle, Yangle, Zangle)
        let viewMatrix = this.camera.ViewMatrix;
        this.toDrawObject3Ds[0].setViewMatrix(viewMatrix);
        this.device.queue.writeBuffer(this.viewMatrixBuffer, 0, new Float32Array(viewMatrix));
        let extent = this.camera.computeViewRectangle();
        this.scene._quadtreePrimitive.selectTilesToRender(extent);
    }
    createPointsForExtent(extent: Rectangle) {
        const vertices = [];
        const a = Ellipsoid.WGS84.radii.x; // 长半轴
        const b = Ellipsoid.WGS84.radii.z; // 短半轴
        let north = extent.north / Math.PI * 180;
        let south = extent.south / Math.PI * 180;
        let west = extent.west / Math.PI * 180;
        let east = extent.east / Math.PI * 180;
        let latStep = (north - south) / 99;
        let lonStep = (east - west) / 199;
        let lat = north;
        let lng = west;
        for (let i = 0; i <= 100; i++) {
            lat = north - i * latStep;
            const sinTheta = Math.sin(lat / 180 * Math.PI);
            const cosTheta = Math.cos(lat / 180 * Math.PI);
            for (let j = 0; j <= 100; j++) {
                lng = west + j * lonStep;
                const sinPhi = Math.sin(lng / 180 * Math.PI);
                const cosPhi = Math.cos(lng / 180 * Math.PI);
                const x = a * cosTheta * cosPhi;
                const y = a * cosTheta * sinPhi;
                const z = b * sinTheta;
                vertices.push(x, y, z);
            }
        }
        return vertices;
    }
    render() {
        this.UpdateData();
        const commandEncoder = this.device.createCommandEncoder();
        const textureView = this.context.getCurrentTexture().createView();
        const renderPassDescriptor: GPURenderPassDescriptor = {
            colorAttachments: [{
                view: textureView,
                clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
                loadOp: 'clear',
                storeOp: 'store',
            }],
        };
        const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
        passEncoder.setVertexBuffer(1, this.uvBuffer);
        passEncoder.setPipeline(this.pipeline);
        passEncoder.setBindGroup(0, this.texTurebindGroup1);
        passEncoder.setBindGroup(1, this.MatrixBindgroup);
        passEncoder.setIndexBuffer(this.indexBuffer, 'uint16');
        this._toDrawTiles.forEach((Tile, index) => {
            passEncoder.setBindGroup(2, this.indexBindGroup, [index * 256])
            passEncoder.setVertexBuffer(0, this.vertexBuffers[index]);
            passEncoder.drawIndexed(this.uint16indices.length);
        })
        this.toDrawObject3Ds.forEach((object3D, index) => {
            passEncoder.setPipeline(object3D.pipeline);
            passEncoder.setIndexBuffer(object3D.indexBuffer, 'uint16');
            passEncoder.setVertexBuffer(0, object3D.vertexBuffer);
            passEncoder.setBindGroup(0, object3D.bindGroup);
            passEncoder.drawIndexed(object3D.indexLength);
        })
        passEncoder.end();
        this.device.queue.submit([commandEncoder.finish()]);
    }
}